﻿using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using Devonline.AspNetCore;
using Devonline.Core;
using Devonline.Entity;
using Microsoft.Extensions.Logging;

namespace Devonline.AuxiliaryTools.FileTools;

/// <summary>
/// sql 文件操作相关的服务
/// TODO TBC 尚未实现从 sql 文件的 insert 脚本中读取数据
/// </summary>
public class SqlFileService : DataFileService, IDataFileService, IFileService
{
    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="logger">日志</param>
    /// <param name="httpSetting">Http配置项</param>
    public SqlFileService(ILogger<SqlFileService> logger, HttpSetting httpSetting) : base(logger, httpSetting) => _fileExtension = AppSettings.DEFAULT_SQL_FILE_EXTENSION;

    /// <summary>
    /// 插入数据时的列名部分
    /// </summary>
    private static string _insertColumns = string.Empty;
    /// <summary>
    /// 隐射到数据库的属性集合
    /// </summary>
    private static PropertyInfo[]? _propertyInfos;
    /// <summary>
    /// 读写时的数据总量
    /// </summary>
    private static long _total = 0;

    /// <summary>
    /// 写入数据到 sql 文件, 每个对象写一行, 此为大数据量写入处理方法
    /// </summary>
    /// <typeparam name="TEntitySet">写入的数据类型</typeparam>
    /// <param name="entitySets">写入的数据</param>
    /// <param name="fileName">文件名</param>
    /// <returns>写入的总行数</returns>
    public override async Task<long> WriteAsync<TEntitySet>(IEnumerable<TEntitySet> entitySets, string? fileName = null)
    {
        var index = 0L;
        if (!entitySets.Any())
        {
            return index;
        }

        BeforeWrite<TEntitySet>();
        _total = entitySets.LongCount();
        var type = typeof(TEntitySet).GetDisplayName();
        fileName = GetFileName<TEntitySet>(fileName);
        _logger.LogInformation($"将写入 {type} 数据 {_total} 行到文件: {fileName} 中!");

        var line = string.Empty;
        using var writer = GetWriter(fileName);

        try
        {
            var tableName = typeof(TEntitySet).GetTableName();
            await writer.WriteLineAsync($"-- {tableName} start --");
            foreach (var entitySet in entitySets)
            {
                line = ConvertTo(entitySet, ++index);
                if (!string.IsNullOrWhiteSpace(line))
                {
                    await writer.WriteLineAsync(line);
                }
            }

            await writer.WriteLineAsync($"-- {tableName} end --");
            _logger.LogInformation($"已写入 {type} 数据 {index} 行到文件: {fileName} 中!");
        }
        catch (Exception ex)
        {
            throw new Exception($"写入 {type} 数据第 {index} 行数据到文件: {fileName} 发生异常, 错误对象: {line}", ex);
        }
        finally
        {
            await writer.FlushAsync();
            writer.Close();
        }

        return index;
    }

    /// <summary>
    /// 转换对象为字符串形式
    /// </summary>
    /// <typeparam name="TEntitySet">对象类型</typeparam>
    /// <param name="entitySet">对象值</param>
    /// <param name="index">当前行号</param>
    /// <returns>转换后的字符串格式</returns>
    protected override string? ConvertTo<TEntitySet>(TEntitySet entitySet, long index)
    {
        if (entitySet is IEntitySet entity)
        {
            var sqls = new List<string>();
            foreach (var propertyInfo in _propertyInfos!)
            {
                sqls.Add(entity.GetSqlStringValue(propertyInfo) ?? "NULL");
            }

            var sql = $"({string.Join(AppSettings.DEFAULT_SPLITER_STRING, sqls)})";
            if ((index - 1) % _httpSetting.Execute.MaxWriteCount == 0)
            {
                sql = _insertColumns + sql;
            }

            if (index == _total || index % _httpSetting.Execute.MaxWriteCount == 0)
            {
                sql += AppSettings.CHAR_SEMICOLON;
            }
            else
            {
                sql += AppSettings.CHAR_COMMA;
            }

            return sql;
        }

        return string.Empty;
    }

    /// <summary>
    /// 写入之前计算全局属性
    /// </summary>
    /// <typeparam name="TEntitySet"></typeparam>
    private void BeforeWrite<TEntitySet>()
    {
        _propertyInfos = GetPropertyInfos<TEntitySet>();
        var quotes = _httpSetting.DatabaseType.GetDatabaseSeparator();
        var left = char.MinValue;
        var right = char.MinValue;
        if (quotes.Length >= 1)
        {
            left = quotes[0];
            right = quotes.Length >= 2 ? quotes[1] : quotes[0];
        }

        _insertColumns = $"INSERT INTO {left}{typeof(TEntitySet).GetTableName()}{right} ({string.Join(AppSettings.DEFAULT_SPLITER_STRING, _propertyInfos.Select(x => left + x.GetColumnName() + right))}) VALUES ";
    }
    /// <summary>
    /// 获取可隐射到数据库的字段列表
    /// </summary>
    /// <typeparam name="TEntitySet"></typeparam>
    /// <returns></returns>
    private static PropertyInfo[] GetPropertyInfos<TEntitySet>() => typeof(TEntitySet).GetProperties().Where(x => x.HasAttribute<ColumnAttribute>() && !x.HasAttribute<NotMappedAttribute>()).ToArray();
}